package cn.byapps.hw.service.impl;

import cn.byapps.hw.dao.*;
import cn.byapps.hw.entity.*;
import cn.byapps.hw.service.ClazzService;
import cn.byapps.hw.service.SerialPKService;
import cn.byapps.hw.vo.ClazzVO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Transactional
@Service
public class ClazzServiceImpl implements ClazzService {

    @Resource
    private ClazzDao clazzDao;
    @Resource
    private SerialPKService serialPKService;
    @Resource
    private StudentDao studentDao;
    @Resource
    private HomeworkDao homeworkDao;
    @Resource
    private HomeworkFileDao homeworkFileDao;
    @Resource
    private TimetableDao timetableDao;
    @Resource
    private TeacherFileDao teacherFileDao;
    @Resource
    private MaterialDao materialDao;
    @Resource
    private StudentLoginDao studentLoginDao;


    @Override
    public void save(Clazz item) {
        clazzDao.save(item);
    }

    @Override
    public List<Clazz> find(Integer pos, Integer rows) {
        int pageNumber = (pos + rows - 1) / rows;
        Pageable pageable = PageRequest.of(pageNumber, rows);
        Page<Clazz> page = clazzDao.findAll(pageable);
        return page.getContent();
    }

    @Override
    public int total() {
        return (int) clazzDao.count();
    }

    @Override
    public void deleteById(Integer id) {
        Clazz clazz = clazzDao.getOne(id);
        List<SerialPK> serialPKS = serialPKService.getClazzByTeacherNums(new Clazz(id, null, null));
        for (SerialPK serialPK : serialPKS) {
            serialPK.setClazz(null);
            serialPK.setTeacher(null);
            serialPK.setCourse(null);
            serialPKService.delete(serialPK);
        }
        Set<Student> stds = clazz.getStudents();
        for (Student s : stds) {
            s.getClazzs().remove(clazz);
        }
        clazzDao.delete(clazz);
    }

    @Override
    public void deleteStudentById(String studentId, Integer clazzId) {
        Optional<Student> s = studentDao.findById(studentId);
        Student student = s.isPresent() ? s.get() : null;
        if (student != null) {
            Optional<Clazz> c = clazzDao.findById(clazzId);
            Clazz clazz = c.isPresent() ? c.get() : null;
            Set<Clazz> newclazzes = new HashSet<>();
            for (Clazz cz : student.getClazzs()) if (cz.getId() != clazz.getId()) newclazzes.add(cz);
            student.setClazzs(newclazzes);
        }
        studentDao.saveAndFlush(student);
    }

    @Override
    public void deleteCourseById(Integer courseId, Integer clazzId) {
        SerialPK serialPK = serialPKService.getByClazzAndCourse(courseId, clazzId);
        if (serialPK != null) {
            for (Material material : materialDao.getBySerialPK(serialPK)) {
                for (StudentLogin studentLogin : studentLoginDao.findByMaterial(material)) {
                    studentLoginDao.delete(studentLogin);
                }
                materialDao.delete(material);
            }
            for (Homework h : homeworkDao.findBySerialPKId(serialPK.getId())) {
                List<HomeworkFile> homeworkFiles = homeworkFileDao.findByHomeworkId(h.getId());
                List<TeacherFile> teacherFiles = teacherFileDao.getByHomeworkId(h.getId());
                if (teacherFiles != null) {
                    for (TeacherFile teacherFile : teacherFiles) {
                        teacherFileDao.delete(teacherFile);
                    }
                }
                if (homeworkFiles != null) {
                    for (HomeworkFile homeworkFile : homeworkFiles) {
                        homeworkFileDao.delete(homeworkFile);
                    }
                }
                homeworkDao.delete(h);
            }
            for (Timetable timetable : timetableDao.getBySerialPK(serialPK)) timetableDao.delete(timetable);
            serialPKService.delete(serialPK);
        }
    }

    @Override
    public void update(Clazz clazz) {
        clazzDao.save(clazz);
    }

    @Override
    public void add(Clazz student) {
        clazzDao.save(student);
    }

    @Override
    public List<ClazzVO> findVO(Integer pos, Integer rows) {
        int pageNumber = (pos + rows - 1) / rows;
        Pageable pageable = PageRequest.of(pageNumber, rows);
        Page<Clazz> page = clazzDao.findAll(pageable);
        List<Clazz> clazzs = page.getContent();
        List<ClazzVO> clazzVOs = new ArrayList<ClazzVO>();
        for (Clazz clazz : clazzs) {
            Set<Teacher> teachers = serialPKService.getClazzByTeacherNums(clazz).stream().map(SerialPK::getTeacher).collect(Collectors.toSet());
            int teacherNums = teachers.size();
            Set<Course> courses = serialPKService.getClazzByTeacherNums(clazz).stream().map(SerialPK::getCourse).collect(Collectors.toSet());
            clazzVOs.add(new ClazzVO(clazz.getId(), clazz.getName(), clazz.getStudents().size(), teacherNums, null, null, null));
        }
        return clazzVOs;
    }

    @Override
    public int total(Integer clazzId) {
        return 0;
    }

    @Override
    public List<ClazzVO> findVO(Integer pos, Integer rows, Integer clazzId) {
        Clazz clazzs = clazzDao.findPageById(clazzId);
        List<ClazzVO> clazzVOs = new ArrayList<ClazzVO>();
        Set<Teacher> teachers = serialPKService.getClazzByTeacherNums(clazzs).stream().map(SerialPK::getTeacher).collect(Collectors.toSet());
        int teacherNums = teachers.size();
        Set<Course> courses = serialPKService.getClazzByTeacherNums(clazzs).stream().map(SerialPK::getCourse).collect(Collectors.toSet());
        int pageNumber = (pos + rows - 1) / rows;
        Pageable pageable = PageRequest.of(pageNumber, rows);
        List<Student> students = studentDao.findPageByClazz(pageable, new Clazz(clazzId, null, null));
        clazzVOs.add(new ClazzVO(clazzs.getId(), clazzs.getName(), clazzs.getStudents().size(), teacherNums, teachers, courses, students));
        return clazzVOs;
    }

}
